package com.peng.scalatest

import scala.collection.mutable


/**
 * 集合
 */
object ScalaTest4_Collections {
  def main(args: Array[String]): Unit = {
    //可以使用JAVA的容器类
    //    val list = new java.util.ArrayList[String]()
    //    list.add("hello")
    //    println(list)
    //
    //    //1、scala中的数组
    //    var arr = Array[Int](1, 2, 3, 4, 5)
    //    arr(0) = 20;
    //    println(arr(0))
    //
    //    //2、链表
    //
    //    // 这里要说到一点，在scala中，容器是分为两种的，一种是可变的(mutable)，一种是不可变的(immutable)
    //    // 2.1、先是不可变的  List   操作方法基本都会返回一个新的List
    //    var linkList = List(1, 2, 3, 4, 5)
    //    linkList = linkList.+:(8) //  +:(element)  在链表最前面添加元素
    //    linkList = 8 +: linkList //  +:(element)  在链表最前面添加元素(与上个方法相同 写法不同）
    //    linkList = linkList.:+(24) //  :+(element)  在链表最后添加元素
    //
    //    // 该方法被称为cons，意为构造，向队列的头部追加数据，创造新的列表。
    //    // 用法为x::list,其中x为加入到头部的元素，无论x是列表与否，它都只将成为新生成列表的第一个元素，
    //    // 也就是说新生成的列表长度为list的长度＋1(btw, x::list等价于list.::(x))
    //    linkList = linkList.::(2) // ::(element)  在列表开头添加元素
    //
    //    var listAdd = List(8, 9)
    //    linkList = linkList.:::(listAdd) // :::(element)  在列表开头添加指定列表的元素,该方法只能用于连接两个List类型的集合
    //    linkList = linkList.++(listAdd) // ++ 该方法用于连接两个集合(列表，数组等)
    //    println(linkList)
    //
    //    //2.2、可变 List
    //
    //    val listBuffer = new ListBuffer[Int]
    //    //可变的集合，添加了+= ，-=这样的方法， 见名思义， +=，-=是在自身上进行修改。 而单纯的 +： ：+  则是生成一个新的集合
    //    listBuffer.+=(1)
    //    listBuffer.+=(2)
    //    listBuffer.+=(3)
    //
    //    //3、Set
    //
    //    //3.1 不可变Set
    //    var set:Set[Int] = Set[Int](1, 2, 3, 4, 5, 6, 1)
    //    println(set)
    //
    //    //3.2 可变Set
    //    var mutableSet = mutable.Set(1, 2, 3, 4, 5)
    //    mutableSet.+=(7)
    //    println(mutableSet)
    //
    //
    //    //4、tuple
    //    val tuple1 = new Tuple1("a")
    //    val tuple2 = new Tuple2("a",2)
    //    val tuple6: (Int, Int, Int, Int, Int, Int) = (1,2,3,4,5,6)
    //    val tuple22: ((Int,Int)=>Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) = ((_: Int)*(_: Int),2,2,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22)
    //    println(tuple22._1)//取元组元素的方式是 变量名._第几个，输出是 <function2>，  函数有x个参数，名字就叫 function x
    //    println(tuple22._1(8, 6))
    //
    //    //tuple的迭代
    //    val iterator: Iterator[Any] = tuple22.productIterator
    //    while(iterator.hasNext){
    //      println(iterator.next())
    //    }


    //5、map
    //5.1 不可变
    //    val map: Map[String, Any] = Map(("name", "张三"), "age" -> 18)
    //    val option: Option[Any] = map.get("name") //返回Option的子类  存在返回Some  不存在返回 None
    //    println(map.getOrElse("name", "ca"))
    //    println(map.getOrElse("nama", "ca"))
    //    val keys: Iterable[String] = map.keys
    //    //迭代
    //    for (elem <- keys) {
    //      println(map.get(elem))
    //    }
    //
    //    //5.2 可变
    //
    //    val mutableMap: mutable.Map[String, Any] = mutable.Map()
    //
    //    mutableMap.put("ha", "hei")
    //    println(mutableMap)


    //6、scala的艺术

    val ints = List(1, 2, 3, 4, 5)
    val listMap = ints.map((_: Int) * 10)

    //不同容器，同样的处理方式，不需要改动代码
    val strings = List("hello world", "new world", "to me")
    //    val strings = Set("hello world","new world","to me")
    //    val strings = Array("hello world","new world","to me")
    val flatMap = strings.flatMap(_.split(" "))
    flatMap.foreach(println)
    val tuples = flatMap.map((_, 1))
    tuples.foreach(println)

    /**
     * 思考以上的处理方式存在什么问题？？
     * 一大批数据，每次经过一次处理后生成的中间结果，n次处理就会多出n份中间结果
     * 解决方式？
     * 思考 iterator迭代器设计模式，为什么会有这种模式？
     * 1、迭代器本身不存放数据，只靠一根指针工作，可以一点点的读取大批量数据的一部分，而不需要一下子将所有数据一次性load出来。
     * 2、如何保证多个线程同时访问数据时指针的问题？  一个线程拿一个单独的迭代器， 自己用自己的指针玩
     *
     *
     */


    /**
     * 迭代器是如何解决上述的 多份中间结果的问题的？
     * 以下是使用迭代器来实现上面相同的功能
     */

    /**
     * next方法是 取出头上的一个元素，然后将自身重新赋予成 除了头上的其他所有元素的集合
     */
    val iterator: Iterator[String] = strings.iterator //得到一个List的迭代器

    /**
     * hasNext方法中，会调用上级iter的next方法 ，并将取出的元素进行传入函数的处理，将结果变为一个iter，对 cur进行赋值
     * next方法，就是对这个cur进行遍历
     * 当cur遍历到最后一个时，会通过hasNext方法中再次去上级iter查看是否存在下一个元素， 有的话继续取出，对cur进行赋值....
     *
     * 简单来说，flatMap的实现就是  将一个集合的每一个元素进行拆分后，每一个元素就又可以是一个独立的元素集合，也就可以成为一个迭代器
     * 上述例子的表现形式类似于： [Iterator{"hello","world"},Iterator{"new","world"},Iterator{"to",""me}]
     * 每次对一个元素生成的迭代器进行遍历， 遍历完成，继续对下一个元素生成迭代器，然后进行遍历， 直到最后一个元素。。。
     */
    val iteratorFlatMap: Iterator[String] = iterator.flatMap(_.split(" ")) //又是得到一个迭代器
    /**
     * map方法就比较简单， hashNext方法也直接调用上层，   以及 直接调用上层的next方法，将结果传入 参数函数中
     */
    val iteratorMap: Iterator[(String, Int)] = iteratorFlatMap.map((_, 1)) //依然得到一个迭代器

    /**
     * 结合源码进行分析， 另外参考image下的图片
     */


    /**
     * 迭代器和之前的最大差别是什么？
     * 发现多次处理，没有产生中间结果，而只是又多包了一层方法而已
     * 个人认为有点类似于 装饰器设计模式 ，一层套一层
     * 之后当某个时刻，调用 foreach这种迭代操作的时候， 才会由下向上，由外到内的进行层层调用，一下子得到最终结果
     * 总体来说，非常的优雅！！！
     */

    val ints1 = new mutable.HashSet[Int]
    val ints2 = new mutable.HashSet[Int]
    ints1 ++= ints2






  }
}
